package xyz.scootaloo.kami.cloud.handler

import io.vertx.core.buffer.Buffer
import io.vertx.ext.web.Route
import io.vertx.ext.web.RoutingContext
import kotlinx.coroutines.CoroutineScope
import org.slf4j.Logger
import xyz.scootaloo.kami.cloud.lang.*
import xyz.scootaloo.kami.cloud.model.core.SC
import xyz.scootaloo.kami.cloud.model.core.StatusCode
import xyz.scootaloo.kami.cloud.model.core.messageOf
import xyz.scootaloo.kami.cloud.verticle.HttpServerVerticle

/**
 * @author flutterdash@qq.com
 * @since 2022/4/10 14:15
 */
typealias CoroutineReqHandler = suspend CoroutineScope.(RoutingContext) -> Unit
typealias AuthMode = AuthenticateMode

enum class AuthenticateMode {
    NONE, JWT, DIGEST
}

val httpRequestRegisterCollects = listOf(
    FileViewHandler, AccountHandler, HeartbeatHandler
)

inline fun <reified T : JsonSerializable> RoutingContext.readBodyAsJson(): T {
    return deserializer(bodyAsJson)
}

fun Route.coroutineHandler(logger: Logger, handler: CoroutineReqHandler) {
    handler { ctx ->
        HttpServerVerticle.launchCoroutine {
            try {
                handler(ctx)
            } catch (err: Throwable) {
                requestErrHandler(ctx, err, logger)
            }
        }
    }
}

private fun requestErrHandler(ctx: RoutingContext, err: Throwable, logger: Logger) {
    if (ctx.response().ended())
        return
    ctx.put(Constant.KEY_HTTP_PROC_ERR, err)
    ctx.reply(SC.FAILURE)
}

fun RoutingContext.queryMillisSeconds(): Long {
    val begin = get<Long>(Constant.KEY_QUERY_BEGIN) ?: return 0
    val finish = get<Long>(Constant.KEY_QUERY_FINISH) ?: currentTimeMillis()
    return finish - begin
}

fun RoutingContext.remoteIpAddress(): String {
    return request().remoteAddress()?.hostAddress() ?: "unknown"
}

fun RoutingContext.reply(buffer: Buffer) {

}

fun RoutingContext.reply(code: SC) {
    reply(null, code)
}

fun <T> RoutingContext.reply(data: T? = null, code: StatusCode = SC.SUCCEED) {
    val message = messageOf(data, code)
    saveResp(this, message)
    json(message)
}

private fun saveResp(ctx: RoutingContext, respBody: Any) {
    ctx.put(Constant.KEY_QUERY_FINISH, currentTimeMillis())
    if (Global.APP_LOG_CONF.enableHttpRecord && Global.APP_LOG_CONF.logRequestWhitResponse) {
        ctx.put(Constant.KEY_HTTP_RESP_STORE, respBody)
    }
}